home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-04-03 | 13.9 KB | 451 lines | [TEXT/MPS ] |
- //----------------------------------------------------------------------------------------
- // UniversalStartup.cp
- // Copyright © 1984-96 by Apple Computer, Inc. All rights reserved.
- //----------------------------------------------------------------------------------------
-
-
- #ifndef __UNIVERSALSTARTUP__
- #include "UniversalStartup.h"
- #endif
-
- // MacApp
-
- #ifndef __UCOREERRORMGR__
- #include "UCoreErrorMgr.h"
- #endif
-
- #ifndef __UCOREUTILITIES__
- #include "UCoreUtilities.h"
- #endif
-
- // Toolbox
-
- #ifndef __DIALOGS__
- #include <Dialogs.h>
- #endif
-
- #ifndef __GESTALT__
- #include <Gestalt.h>
- #endif
-
- #ifndef __RESOURCES__
- #include <Resources.h>
- #endif
-
- #ifndef __FONTS__
- #include <Fonts.h>
- #endif
-
- #ifndef __TOOLUTILS__
- #include <ToolUtils.h>
- #endif
-
- #ifndef __LOWMEM__
- #include <LowMem.h>
- #endif
-
- //••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
- // B E G I N U N I V E R S A L C O D E
- //
- // The following is universal code. That is, code that must be compiled to run on any
- // processor. This is because this is the code that is called during startup, but after
- // we've checked for PPC so this can be PPC code. This code will properly initialize the
- // toolbox, thus an alert can be shown if necessary. It must not make any calls into code
- // that is not "universal" code.
- //
- //••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
-
- #pragma push
- #if !qPowerPC
- #pragma processor 68000
- #endif
-
- Boolean gHasProcessMgr; // saved from InitToolBox for configuration info
- Boolean gIsOnlyBackground; // saved from InitToolBox for configuration info
- Boolean gIsHighLevelEventAware; // saved from InitToolBox for configuration info
- short gProcessor; // saved from ValidateHardware for configuration info
- Boolean gHasFPU; // saved from ValidateHardware for configuration info
-
- Size gSizeObjectHeap;
- Size gSizeHeapIncrement;
- Size gSizeTempReserve;
- Size gSizeLowSpaceReserve;
- Size gStackTot;
- //========================================================================================
- // GLOBAL Functions
- //========================================================================================
-
- //----------------------------------------------------------------------------------------
- // ClearTheFPU: Essential one-time initialization
- //
- // INLINE 0x42A7, // CLR.L -(A7)
- // 0x42A7, // CLR.L -(A7)
- // 0xF21F, 0x9800; // FMOVEM (A7)+, FPCR/FPSR
- //----------------------------------------------------------------------------------------
- #if !qPowerPC
- static void ClearTheFPU() = {0x42A7, 0x42A7, 0xF21F, 0x9800};
- #endif
-
- static void InitToolBox();
- static void LockSegment(ConstStr255Param name, Ptr optionalUnload = NULL);
- static void FailedInitToolBox();
- static void DoRealInitToolBox();
- static void ExpandHeap();
- static void SetStackSpace(long numBytes);
-
- extern pascal void _DataInit(); // Routine in the A5 globals initializer
- void FunctionInMAMain(); // address of any old routine in the MAMain segment
-
-
- //----------------------------------------------------------------------------------------
- // FunctionInMAMain
- //----------------------------------------------------------------------------------------
- #pragma segment MAMain
- // Must be in the MAMain segment
- void FunctionInMAMain()
- {
- }
-
- //----------------------------------------------------------------------------------------
- // UniversalStartup
- //----------------------------------------------------------------------------------------
- #pragma segment Main
- // Must be in the Main segment since all other segments get unloaded from here.
-
- void UniversalStartup()
- {
- Boolean validProcessor = ValidateProcessor();
-
- #if !qPowerPC
- // the main procedure is always compiled with universal code so, the FPU must be
- // reset before it is used. We could get spurious crashes or worse. Remember:
- // 2+2=4 every time!
- if (gHasFPU)
- ClearTheFPU();
- #endif
-
- InitToolBox();
-
- if (!validProcessor)
- {
- AlertUnsupportedConfiguration();
- }
-
- ExpandHeap();
- } // UniversalStartup
-
- //----------------------------------------------------------------------------------------
- // ValidateProcessor:
- //----------------------------------------------------------------------------------------
- #pragma segment MAMiniInit
-
- Boolean ValidateProcessor()
- {
- long response;
- OSErr err = Gestalt(gestaltProcessorType, &response);
- gProcessor = (short)response;
-
- err = Gestalt(gestaltFPUType, &response);
- gHasFPU = response != gestaltNoFPU;
-
- Boolean isSupported = true;
-
- // Run the gauntlet of hardware support tests using the conditionally set constants. If any
- // single test fails then the app is considered unsupported on this machine.
-
- if (qNeedsMC68020)
- isSupported &= ((gProcessor != gestalt68000) &&
- (gProcessor != gestalt68010));
-
- if (qNeedsMC68030)
- isSupported &= ((gProcessor != gestalt68000) &&
- (gProcessor != gestalt68010) &&
- (gProcessor != gestalt68020));
-
- if (qNeedsMC68040)
- isSupported &= ((gProcessor != gestalt68000) &&
- (gProcessor != gestalt68010) &&
- (gProcessor != gestalt68020) &&
- (gProcessor != gestalt68030));
-
- if (qNeedsFPU)
- isSupported &= gHasFPU;
-
- return isSupported;
- } // ValidateProcessor
-
- //----------------------------------------------------------------------------------------
- // UnsupportedConfiguration:
- //----------------------------------------------------------------------------------------
- #pragma segment MAMiniInit
-
- void AlertUnsupportedConfiguration()
- {
- SetCursor(&qd.arrow);
-
- // This alert is set to preload
- Alert(phUnsupportedConfiguration, NULL);
- ExitToShell(); // leave the application pronto!
- } // AlertUnsupportedConfiguration
-
- //----------------------------------------------------------------------------------------
- // FailedInitToolBox: This procedure is intended to be in "Main" which is already loaded
- //----------------------------------------------------------------------------------------
- #pragma segment Main
-
- void FailedInitToolBox()
- {
- #if qDebug
- DebugStr((StringPtr)"\pNot enough room to initialize ToolBox managers");
- #endif
- ExitToShell();
- } // FailedInitToolBox
-
- //----------------------------------------------------------------------------------------
- // LockSegment:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
-
- void LockSegment(ConstStr255Param name, Ptr optionalUnload)
- {
- SetResLoad(FALSE);
- Handle h = GetNamedResource('CODE', name);
- OSErr theErr = ResError();
- SetResLoad(TRUE);
- if (h != NULL)
- {
- short attrs = GetResAttrs(h);
- if ((attrs & resLocked) != resLocked)
- {
- short itsSize = GetMaxResourceSize(h);
- if (*h != NULL && optionalUnload)
- {
- UnloadSeg(optionalUnload);
- EmptyHandle(h);
- }
- short resFile = HomeResFile(h);
- short fileAttrs = GetResFileAttrs(resFile);
-
- SetResFileAttrs(resFile, mapReadOnly); // keep the changed bit from coming on and causing an update to disk later
- SetResAttrs(h, (attrs | resLocked));
- SetResFileAttrs(resFile, fileAttrs);
-
- if (*h == NULL)
- {
- ReserveMem(itsSize);
- LoadResource(h); // now try to haul the segment in low
- }
- if (*h != NULL)
- {
- HNoPurge(h);
- HLock(h);
- }
- }
- }
- else if (theErr != resNotFound) // it's OK if the segment doesn't exist
- FailedInitToolBox();
- }
-
- //----------------------------------------------------------------------------------------
- // DoRealInitToolBox:
- //----------------------------------------------------------------------------------------
- #pragma segment MAMiniInit
-
- void DoRealInitToolBox()
- {
- // Check for process mgr then check for background only mode
- long response;
- if ((Gestalt(gestaltOSAttr, &response) == noErr) && (((response >> gestaltLaunchControl) & 1) != 0))
- {
- gHasProcessMgr = true; // save it for later
- ProcessSerialNumber psn;
- psn.highLongOfPSN = 0;
- psn.lowLongOfPSN = kCurrentProcess;
-
- ProcessInfoRec info;
- info.processInfoLength = sizeof(ProcessInfoRec);
- info.processName = NULL;
- info.processAppSpec = NULL;
-
- if (GetProcessInformation(&psn, &info) == noErr)
- {
- gIsOnlyBackground = (info.processMode & modeOnlyBackground) ? true : false;
- gIsHighLevelEventAware = (info.processMode & modeHighLevelEventAware) ? true : false;
- }
- }
-
- // Are we background only? If so, bail out...this isn't yet supported by the code.
- if (!gIsOnlyBackground)
- {
- // init the toolbox managers
- InitGraf(&qd.thePort);
- InitFonts();
- InitWindows(); // creates non-relocatable for the WM port
-
- // _DON'T_ flush disk-inserted or os events or you'll be sorry!
- FlushEvents(everyEvent - diskMask - osMask, 0);
-
- InitMenus();
- TEInit();
- InitDialogs(NULL);
-
- InitCursor();
-
- gToolBoxInitialized = TRUE;
-
- // The refnum where the application's resources should be found
- gApplicationRefNum = LMGetCurMap(); // Don't use MACurResFile, it's not universal
- gCodeRefNum = LMGetCurApRefNum(); // Not necessarily the same as gApplicationRefNum under some IDE's
-
- // -1 == 0xFFFFFFFF, the largest 32 bit address. Our routine StripLong uses a
- // pre-stripped address gStrippedAddress to avoid the yucky MPW glue.
- gStrippedAddress = StripAddress((Ptr) - 1);
- }
- else
- {
- #if qDebug
- DebugStr((StringPtr)"\pBackground-only apps not currently supported");
- #endif
- ExitToShell();
- }
- } // DoRealInitToolBox
-
- //----------------------------------------------------------------------------------------
- // InitToolBox:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
-
- void InitToolBox()
- {
- const short kBreathingRoom = 1024; // Amount of heap space needed for init
-
- #if qSegments
- // the heap and stack don't overlap. So there's enough room to init the managers. Make
- // sure that the MAMiniInit Segment can be loaded and that there's still a little Room
- // after that. */
-
- #if !qModelCFM && !defined(__MWERKS__)
- UnloadSeg(&_DataInit); // Toss some ballast
- #endif
-
- // "MAMain" this is MacApp's own code that must be resident even before/ during the
- // UMemory startup. GetNamedResource will call RsrvMem which locates the handle as low
- // in memory as possible. We will then lock it there just like "Main". In order for
- // this to work correctly the build system will have to have set the locked bit on the
- // MAMain resource.
-
- // These are the only 2 resources that MABuild would set to locked.
- // The following is necessary because some development environments don't automatically
- // set these this resource to locked (which means they will get loaded hi in memory).
- // We'll just dynamically fix that right here! (if necessary)
- LockSegment("\pMain");
- LockSegment("\pMAMain", (Ptr)FunctionInMAMain);
-
- Handle seg = GetNamedResource('CODE', "\pMAMiniInit");
- if (seg)
- HNoPurge(seg); // don't let it get squished out of the heap when the grow zone
- // might get called below. However, since it is not locked it will
- // float up to the top of the heap when it is entered at
- // DoRealInitToolBox.
-
- #endif // qSegments
-
- // Attempt to ensure that there is going to be kBreathingRoom bytes available in the
- // heap so that when the actual toolbox managers are initialized there is a
- // significantly reduced chance that they will express their displeasure with us
- // through SysErr -25 or -2. If the space is not currently available in the zone as
- // shown by PurgeSpace then attempting to allocate it will let growzoneproc operate
- // and grow the zone a little, as necessary. If, after that, we haven't been able to
- // get the breathing room we desire then just give up and fade silently away. (Like
- // the old soldier, not the old executive).
-
- Size totalSize = 0;
- Size contigSize = 0;
- PurgeSpace(&totalSize, &contigSize);
-
- if (totalSize >= kBreathingRoom)
- DoRealInitToolBox();
- else
- {
- Handle breathingRoom = NewHandle(kBreathingRoom);
- if (breathingRoom != NULL) // get the grow space
- {
- DisposeHandle(breathingRoom);
- DoRealInitToolBox();
- }
- else
- FailedInitToolBox(); // Give up
- }
- } // InitToolBox
-
- //----------------------------------------------------------------------------------------
- // ExpandHeap:
- //----------------------------------------------------------------------------------------
- #pragma segment Main
-
- void ExpandHeap()
- {
- // Sum up the standard memory requirements
- // and add on the processor dependent memory requirements
- // Then expand the heap while preserving the requested stack space
-
- const ResType memResType[2] = { 'mem!'
- #if qPowerPC
- , 'ppc!'
- #else
- , '68k!'
- #endif
- };
-
- for (int whichType = 0; whichType < 2; whichType++)
- {
- ResType whichResType = memResType[whichType];
- ResNumber rsrcCnt = CountResources(whichResType);
- for (ResNumber i = 1; i <= rsrcCnt; ++i)
- {
- Handle h = GetIndResource(whichResType, i);
- {
- const Mem &memH = **((MemHandle)h);
-
- gSizeObjectHeap += memH.objectHeap;
- gSizeHeapIncrement += memH.heapIncrement;
- gSizeTempReserve += memH.codeVal;
- gSizeLowSpaceReserve += memH.lowSpaceVal;
- gStackTot += memH.stackVal;
- }
- ReleaseResource(h);
- }
- }
-
- SetStackSpace(gStackTot);
-
- MaxApplZone();
- } // ExpandHeap
-
- //----------------------------------------------------------------------------------------
- // SetStackSpace:
- //----------------------------------------------------------------------------------------
- #pragma segment MAMiniInit
-
- void SetStackSpace(long numBytes)
- {
- // Make sure numBytes is even (don't use the "odd" macro in case it outlines
- if (numBytes & 0x00000001)
- numBytes++;
-
- long newLimit = (long)LMGetCurStackBase() - numBytes;
- if ((long)GetApplLimit() > newLimit)
- SetApplLimit((Ptr)newLimit);
- } // SetStackSpace
-
- #pragma pop
-
- //••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
- // E N D U N I V E R S A L C O D E
- //••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
-
- //----------------------------------------------------------------------------------------
- // End of UniversalStartup.cp
-
- #pragma segment Inline
-